package com.qd.core.service.app;

import cn.hutool.core.util.PhoneUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.core.weixinmanager.domain.MiddleUserDTO;
import com.cdqidi.core.weixinmanager.model.MiddleUser;
import com.cdqidi.core.weixinmanager.service.MiddleUserService;
import com.cdqidi.core.weixinmanager.service.OrgWxConfigService;
import com.cdqidi.core.weixinmanager.service.wx.WxApiService;
import com.cdqidi.exception.ApiException;
import com.cdqidi.util.RedisTemplateUtil;
import com.jfinal.weixin.sdk.api.SnsAccessToken;
import com.qd.common.panda.config.PandaParkConfigDTO;
import com.qd.common.sys.domain.entity.login.AppLoginUserDTO;
import com.qd.common.sys.domain.entity.login.AppWxLoginUserDTO;
import com.qd.common.sys.domain.login.LoginUser;
import com.qd.system.service.person.AuthTokenService;
import com.qd.system.service.user.BaseUserInfoService;
import com.qd.system.sms.SmsService;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 公众号登录
 *
 * @author sjk
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class AppWxLoginService {

    @Resource
    private MiddleUserService middleUserService;
    @Resource
    private OrgWxConfigService orgWxConfigService;
    private final BaseUserInfoService baseUserInfoService;
    private final PandaParkConfigDTO parkConfig;
    private final AppLoginService appLoginService;
    private final SmsService smsService;
    private final AuthTokenService authTokenService;
    @Resource
    private HttpServletRequest request;
    @Resource
    private WxApiService wxApiService;

    private final StringRedisTemplate stringRedisTemplate;

    /**
     * 微信公众号登录
     *
     * @param openid  微信openid
     * @param unionId 微信unionId
     * @param appId   公众号appId
     * @return token
     */
    @Transactional(rollbackFor = Exception.class)
    public String isWxLogin(String openid, String unionId, String appId) {
        LoginUser loginUser = authTokenService.getLoginUser(request);
        if (null != loginUser) {
            authTokenService.refreshToken(loginUser);
            return loginUser.getToken();
        }
        List<MiddleUser> list = middleUserService.getListByUnionId(unionId);
        if (list.isEmpty()) {
            return null;
        }
        MiddleUser wxMiddleUser = list.stream().filter(user -> user.getAppId().equals(appId)).findFirst().orElse(null);
        MiddleUser wxaMiddleUser = list.stream().filter(user -> user.getAppId().equals(parkConfig.getDefaultMiniProgramAppId())).findFirst().orElse(null);
        if (null == wxMiddleUser && null != wxaMiddleUser) {
            //自动绑定微信公众号
            MiddleUserDTO middleUserDTO = new MiddleUserDTO();
            middleUserDTO.setRId(IdWorker.getIdStr());
            middleUserDTO.setAppId(appId);
            middleUserDTO.setMobile(wxaMiddleUser.getMobile());
            middleUserDTO.setBindTime(LocalDateTime.now());
            middleUserDTO.setOpenid(openid);
            middleUserDTO.setUnionId(unionId);
            middleUserDTO.setUserId(wxaMiddleUser.getUserId());
            middleUserService.save(middleUserDTO);
            wxaMiddleUser.freeData();
            wxMiddleUser = middleUserService.dtoToModel(middleUserDTO);
            middleUserDTO.freeData();
        }
        if (null == wxMiddleUser) {
            return null;
        }
        return appLoginService.login(wxMiddleUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @SneakyThrows
    public String register(AppWxLoginUserDTO appWxLoginUserDTO) {
        if (!PhoneUtil.isPhone(appWxLoginUserDTO.getMobile())) {
            throw new ApiException("请输入正确的手机号码");
        }
        boolean b = smsService.checkVerificationCode(appWxLoginUserDTO.getMobile(), appWxLoginUserDTO.getVerCodeId(), appWxLoginUserDTO.getVerCode());
        if (!b) {
            log.error("验证码输入错误,mobile: {},verCodeId: {},verCode: {}", appWxLoginUserDTO.getMobile(), appWxLoginUserDTO.getVerCodeId(), appWxLoginUserDTO.getVerCode());
            throw new ApiException("验证码输入错误");
        }
        String appId = parkConfig.getDefaultAppId();
        boolean exists = orgWxConfigService.isExistsById(appId);
        if (Boolean.FALSE.equals(exists)) {
            throw new ApiException("appId不存在");
        }
        AppLoginUserDTO dto = new AppLoginUserDTO();
        dto.setAppId(appId);
        dto.setMobile(appWxLoginUserDTO.getMobile());
        dto.setOpenid(appWxLoginUserDTO.getOpenid());
        if (StringUtils.hasLength(appWxLoginUserDTO.getUnionId())) {
            dto.setUnionId(appWxLoginUserDTO.getUnionId());
        }
        final String uid = baseUserInfoService.getMobileToUid(appWxLoginUserDTO.getMobile());
        LocalDateTime bindTime = LocalDateTime.now();
        appLoginService.buildBind(dto.getMobile(), uid, bindTime);
        MiddleUser middleUser = Optional.ofNullable(appLoginService.buildWxMiddleUser(dto, uid, bindTime)).orElseThrow(() -> new ApiException("用户关系信息为空"));

        String login = appLoginService.login(middleUser, dto.getPromotionCode());

        dto.freeData();
        middleUser.freeData();

        return login;
    }

    @Transactional(rollbackFor = Exception.class)
    public String buildRedirectUrl(String code, String state, String id) {
        String key = RedisTemplateUtil.buildKey(state, true);
        final String s = stringRedisTemplate.opsForValue().get(key);
        if (StringUtils.hasLength(s) && s.equals(state)) {
//            stringRedisTemplate.delete(key);
            String idKey = RedisTemplateUtil.buildKey(id, true);
            String redirectUrl = stringRedisTemplate.opsForValue().get(idKey);
            if (!StringUtils.hasLength(redirectUrl)) {
                redirectUrl = "path=" + parkConfig.getDomain() + "/gy_shop/#/";
                if (log.isDebugEnabled()) {
                    log.debug("跳转地址为空，跳到首页");
                }
            }
            if (log.isDebugEnabled()) {
                log.debug("redirectUrl: {}", redirectUrl);
            }
            int pathIndex = redirectUrl.indexOf("path");
            if (pathIndex == -1) {
                throw new ApiException("path不能为空");
            }
            StringBuilder url = new StringBuilder(redirectUrl.substring(pathIndex + 5));
            if (log.isDebugEnabled()) {
                log.debug("redirectUrl1: {}", redirectUrl);
            }
            LoginUser loginUser = authTokenService.getLoginUser(request);
            if (null == loginUser) {
                SnsAccessToken snsAccessToken = wxApiService.getSnsAccessToken(code, parkConfig.getDefaultAppId());
                if (null != snsAccessToken) {
                    final String token = isWxLogin(snsAccessToken.getOpenid(), snsAccessToken.getUnionid(), parkConfig.getDefaultAppId());
                    if (StringUtils.hasLength(token)) {
                        url.append(flag(url)).append("token=").append(token);
                    } else {
                        if (StringUtils.hasLength(snsAccessToken.getOpenid())) {
                            url.append(flag(url)).append("openid=");
                            url.append(URLEncoder.encode(snsAccessToken.getOpenid(), StandardCharsets.UTF_8));
                        }
                        if (StringUtils.hasLength(snsAccessToken.getUnionid())) {
                            url.append(flag(url)).append("unionId=");
                            url.append(URLEncoder.encode(snsAccessToken.getUnionid(), StandardCharsets.UTF_8));
                        }
                    }
                }
            } else {
                if (url.indexOf("token") == -1) {
                    url.append(flag(url)).append("token=").append(loginUser.getToken());
                }
            }
            return url.toString();
        }
        return null;
    }

    public String flag(StringBuilder url) {
        int i = url.indexOf("?");
        if (i == -1) {
            return "?";
        } else {
            return "&";
        }
    }
}
